#!/usr/bin/env bash

##############################################################################################
# THIS MODULE INCLUDES ALL THE ACTIONS INTENDED TO MANAGE THE APPS INSTALLED FROM THE DATABASE
##############################################################################################

case $2 in
  '') echo " USAGE: $AMCLI $1 [ARGUMENT]"; exit;;
esac

########################################
# FUNCTIONS RELATED TO THE APP'S REMOVAL
########################################

function _remove_check_removals() {
	if test -f "$AMCACHEDIR"/unavailable-args; then
		echo -e "-----------------------------------------------------------------------\n"
		if [ "$AMCLI" == am ] 2>/dev/null; then
			echo -e " 💀 ERROR, the following programs you want to remove are NOT in $APPSPATH :\n\n$(cat "$AMCACHEDIR"/unavailable-args | sort)"
		else
			echo -e " 💀 ERROR, the following programs you want to remove are NOT in\n    $APPSPATH :\n\n$(cat "$AMCACHEDIR"/unavailable-args | sort)"
		fi
		echo -e '\n INVALID "APPNAME"!'
		echo -e "\n-----------------------------------------------------------------------\n"
		echo ' ◆ INSTALLED PROGRAMS/VALID ARGUMENTS (SEE THE "APPNAME" COLUMN):'
		$AMCLIPATH -f | grep -v "STANDALONE PROGRAMS MANAGED"; rm "$AMCACHEDIR"/unavailable-args
		echo -e "-----------------------------------------------------------------------"
		exit
	else
		exit
	fi
}

function _REMOVE() {
	if ls "$APPSPATH"/$arg > /dev/null 2>&1; then
		$SUDOCOMMAND "$APPSPATH"/$arg/remove && sleep 0.5 && echo ' ◆ "'"$(echo $arg | tr a-z A-Z)"'" HAS BEEN SUCCESSFULLY REMOVED!'
	else
		echo " - $arg" >> "$AMCACHEDIR"/unavailable-args
	fi
}

function _remove() {
	if ls "$APPSPATH"/$arg > /dev/null 2>&1; then
		case $arg in
		*) 
			$SUDOCOMMAND echo "" > /dev/null; read -p ' ◆ DO YOU WISH TO REMOVE "'"$(echo $arg | tr a-z A-Z)"'" (Y,n)?' yn
			case $yn in
			[Nn]* ) 
				echo ' - "'"$(echo $arg | tr a-z A-Z)"'" HAS NOT BEEN REMOVED!'; echo "";;
			[Yy]*|* ) 
				$SUDOCOMMAND "$APPSPATH"/$arg/remove && sleep 0.5 && echo ' ◆ "'"$(echo $arg | tr a-z A-Z)"'" HAS BEEN SUCCESSFULLY REMOVED!';;
			esac
		esac
	else
		echo " - $arg" >> "$AMCACHEDIR"/unavailable-args
	fi
}

######################################
# FUNCTION TO DOWNGRADE INSTALLED APPS
######################################

function _do_rollback() {
	if test -f "$APPSPATH"/"$2"/AM-updater; then
		if test -f "$APPSPATH"/"$2"/"$2"-rollback; then
			cd "$APPSPATH"/"$2" || return
			./"$2"-rollback
			exit
		elif grep -q "api.github.com" "$APPSPATH"/"$2"/AM-updater; then
			cd "$APPSPATH"/"$2" || return
			rm -f "$AMCACHEDIR/rollback-args";
			extension=$(cat ./version | tr '.' '\n' | tail -1)
			if grep -q "^REPO=" ./AM-updater; then
				REPO=$(grep -i "REPO=" ./AM-updater | grep -o -P '(?<=").*(?=")')
			elif grep -q "^SITE=" ./AM-updater; then
				REPO=$(grep -i "SITE=" ./AM-updater | grep -o -P '(?<=").*(?=")')
			fi
			entries_list=$(grep "^version=" ./AM-updater | sed '1,${ s/version=$(//g; s/head -1)/head -100/g; s#$REPO#'"$REPO"'#g; s#releases/latest#releases#g; s#releases #releases?per_page=100 #g; }')
			printf "%s\n" "$(eval "$entries_list")" | tr ' ' '\n' | grep -i "$extension$" >> "$AMCACHEDIR/rollback-args"
			if ! grep -q "[0-9]" "$AMCACHEDIR"/rollback-args; then
				echo " ERROR: No valid links found, sorry!"
				exit
			else
				echo "-----------------------------------------------------------------------"
				echo "You have chosen to roll back $2."
				echo "Rollback will be done from https://github.com/$REPO"
				echo "-----------------------------------------------------------------------"
				printf "Select a URL from this menu (read carefully) or press CTRL+C to abort:\n-----------------------------------------------------------------------\n"; sleep 1;
				select d in $(cat "$AMCACHEDIR/rollback-args"); do test -n "$d" && break; echo ">>> Invalid Selection"; done

				cp ./AM-updater ./AM-rollback
				sed -i 's/version0/#version0/g' ./AM-rollback

				if test -f ./"$2".zsync; then mv ./"$2".zsync ./"$2".zsync.old;	fi

				if wget --version | head -1 | grep -q ' 1.'; then
					sed -i '/wget/c\wget -q --show-progress '"$d"'' ./AM-rollback
				else
					sed -i '/wget/c\wget '"$d"'' ./AM-rollback
				fi
				./AM-rollback
				rm -f ./AM-rollback

				if test -f ./"$2".zsync.old; then mv ./"$2".zsync.old ./"$2".zsync; fi

				echo "$d" > ./version
				_clean_amcachedir
				_list_updatable_apps
				echo -e "\nROLLBACK SUCCESSFUL!"
				exit
			fi
		else
			echo " The option \"$1\" only works for https://github.com"; exit
		fi
	else
		echo " No AM-updater available for \"$2\", cannot detect any URL!"; exit
	fi
}

#############################################
# FUNCTIONS TO PREVENT THE APPS TO BE UPDATED
#############################################

function _do_lock() {
	while [ -n "$1" ]; do
		if test -f "$APPSPATH"/$2/AM-updater; then
			case $2 in
				*)
					read -p " Do you wish to keep $2  at the current version (y,N)?" yn
					case $yn in
						[Yy]* )
							mv "$APPSPATH"/$2/AM-updater "$APPSPATH"/$2/AM-LOCK 1>/dev/null &&
							echo " $2 has been locked at current version!"
							exit
							;;
						[Nn]*|* )
							echo " Operation aborted!"
							exit
							;;
					esac
					;;
			esac
		else
			echo -e '\n '"$(echo $AMCLI | tr a-z A-Z)"' cannot manage updates for '$2', "AM-updater" file not found!\n'; exit
			exit
		fi
	done
}

function _do_unlock() {
	while [ -n "$1" ]; do
		if test -f "$APPSPATH"/$2/AM-LOCK; then
			case $2 in
				*)
					read -p " Do you wish to unlock updates for $2 (Y,n)?" yn
					case $yn in
						[Nn]* )
							echo " $2 is still locked at current version!"
							exit
							;;
						[Yy]*|* )
							mv "$APPSPATH"/$2/AM-LOCK "$APPSPATH"/$2/AM-updater 1>/dev/null
							echo ' '$2' can now receive updates!'
							exit
							;;
					esac
					;;
			esac
		else
			echo ' '$2' cannot be unlocked, "AM-LOCK" file not found!'; exit
		fi
	done
}

################################################################
# FUNCTIONS TO BACKUP/RESTORE THE INSTALLED APPS USING SNAPSHOTS
################################################################

function _backup() {
	case $arg in
	'')
		echo " Specify the name of a program to back up"; echo ""; exit;;
	*)
		if test -f "$APPSPATH"/$arg/remove; then
			echo ""; read -p " Do you wish to backup the current version of $arg (y,N)?" yn
			case $yn in
			[Yy]* )
				mkdir -p "$HOME/.am-snapshots/$arg"
				cp -r "$APPSPATH"/$arg "$HOME/.am-snapshots/$arg/$(date +%F-%X | sed 's/://g' | sed 's/-//g')"
				echo -e "\n SAVED in $HOME/.am-snapshots/$arg\n";;
			[Nn]*|* )
				echo ""; echo " OPERATION ABORTED!"; echo "";;
			esac
		else
			echo -e "\n '$arg' is not a valid argument or is not installed.\n"
		fi
	esac
}

function _do_backup() {
	while [ -n "$1" ]; do
		rm -f "$AMCACHEDIR"/backup-args;
		echo "$@" | tr ' ' '\n' >> "$AMCACHEDIR"/backup-args && echo STOP >> "$AMCACHEDIR"/backup-args;
		ARGS=$(tail -n +2 "$AMCACHEDIR"/backup-args)
		for arg in $ARGS; do
			if [ $arg == STOP ]; then
				exit
			else
				_backup
			fi
		done
	done
}

function _overwrite() {
	case $arg in
	'')
		echo " Specify the name of a program to overwrite"; echo "";;
	*)
		if test -f "$APPSPATH"/$arg/remove; then
			echo ""; read -p " Do you wish to overwrite this version of $arg with an old one (y,N)?" yn
			case $yn in
			[Yy]* )
				printf "\n Please, select a snapshot or press CTRL+C to abort:\n\n"; sleep 1;
				select d in $HOME/.am-snapshots/$arg/*; do test -n "$d" && break; echo ">>> Invalid Selection"; done
				cp -r --backup=t $d/* "$APPSPATH"/$arg/
				rm -R -f ./tmp "$APPSPATH"/$arg/*~
				echo -e "\n RESTORE COMPLETED SUCCESSFULLY!\n";;
			[Nn]*|* )
				echo ""; echo " OPERATION ABORTED!"; echo "";;
			esac
		else
			echo ""; echo " '$arg' is not a valid argument or is not installed."; echo ""
		fi
	esac
}

function _do_overwrite() {
	while [ -n "$1" ]; do
		rm -f "$AMCACHEDIR"/overwrite-args
		echo "$@" | tr ' ' '\n' >> "$AMCACHEDIR"/overwrite-args && echo STOP >> "$AMCACHEDIR"/overwrite-args
		ARGS=$(tail -n +2 "$AMCACHEDIR"/overwrite-args)
		for arg in $ARGS; do
			if [ $arg == STOP ]; then
				exit
			else
				_overwrite
				_remove_info_files
			fi
		done
	done
}

##############################################
# FUNCTION TO CONVERT TYPE2 APPIMAGES TO TYPE3
##############################################

function _nolibfuse_if_zsync_file_exists() {
	if test -f ./*.zsync; then
		echo "-----------------------------------------------------------------------"
		echo -e " Warning! Your AppImage uses \"zsync\" to update. The .zsync file will\n no longer work and will be removed.\n"
		echo -e " If your \"AM-updater\" script can compare versions, the update method\n will be changed, by downloading the new AppImage version in full,\n from the source.\n"
		read -p " Do you want to proceede anyway (N,y)?" yn
		case "$yn" in
		'y'|'Y') echo "-----------------------------------------------------------------------";;
		'n'|'N'|*) echo "-----------------------------------------------------------------------"; exit;;
		esac
	fi
}

function _nolibfuse_download_appimagetool() {
	wget -q "$(curl -Ls $HeaderAuthWithGITPAT https://api.github.com/repos/probonopd/go-appimage/releases \
		| grep -v zsync | grep -i continuous | grep -i appimagetool | grep -i "$(uname -m)" | grep browser_download_url \
		| cut -d '"' -f 4 | head -1)" -O appimagetool
	chmod a+x ./appimagetool
}

function _nolibfuse_command_to_convert_to_type3_appimage() {
	chmod 0755 ./squashfs-root
	ARCH="$(uname -m)" VERSION=$(./appimagetool -v | grep -o '[[:digit:]]*') ./appimagetool -s ./squashfs-root > /dev/null 2> /dev/null
}

function _nolibfuse_if_appimage_has_been_converted() {
	rm -R -f ./appimagetool ./squashfs-root
	if test -f ./AM-updater; then
		if test -f ./*.zsync; then
			rm -f ./*.zsync
		fi
		if ! grep -q 'nolibfuse' ./AM-updater; then
			echo -e '\necho y | '$AMCLIPATH' nolibfuse $APP' >> ./AM-updater
			echo -e "\n The next update may replace this AppImage with a Type2 one\n so I added this command to the bottom of the \"AM-updater\" script!"
		fi
	fi
	echo -e "\n Contact the upstream developers to make them officially switch to Type3! \n"
	read -p " Do you wish to remove the old Type2 AppImage (Y,n)?" yn
	case $yn in
	[Nn]* )
		exit
		;;
	[Yy]*|* )
		rm -R -f ./*.old
		if test -f ./*.zsync; then
			rm -f ./*.zsync
		fi
		exit
		;;
	esac
}

function _do_nolibfuse() {
	cd "$APPSPATH" || exit 1
	if test -f "./$2/$2" 2>/dev/null; then
		cd ./"$2" || return
		if [ -z "$(strings -d "./$2" 2>/dev/null | grep -F 'if you run it with the --appimage-extract option')" ] 2>/dev/null; then
			echo " ⚠️ Error: $(echo "${2}" | tr a-z A-Z) is NOT an AppImage."
			exit
		else
			if [ -z "$(strings -d "./$2" 2>/dev/null | grep -F 'AppImages require FUSE to run')" ] 2>/dev/null; then
				echo " ◆ $(echo "${2}" | tr a-z A-Z) is already a Type3 AppImage."
				exit
			else
				_nolibfuse_if_zsync_file_exists
				_nolibfuse_download_appimagetool
				echo -ne " ...extracting the AppImage\r"
				./"$2" --appimage-extract 2> /dev/null | grep -v "squashfs-root"
				echo -ne " ...trying to convert in Type3 AppImage\r"
				_nolibfuse_command_to_convert_to_type3_appimage
				if test -f ./*.AppImage; then
					_remove_info_files
					mv ./"$2" ./"$2".old
					mv ./*.AppImage ./"$2"
					echo " ◆ $(echo "$2" | tr a-z A-Z) has been converted to Type3 AppImage."
					_nolibfuse_if_appimage_has_been_converted
				else
					metainfodir=$(find ./squashfs-root -type d -name metainfo | grep "share/metainfo" | head -1)
					if [ -z "$metainfodir" ]; then
						echo " 💀Errors while trying to export $(echo "${2}" | tr a-z A-Z) from Type2 AppImage. Aborted."
						rm -R -f ./appimagetool ./squashfs-root
						exit
					else
						cd "$metainfodir" || return
						rm -R -f ./*.xml
						cd - > /dev/null || return
					fi
					echo -ne " ...found Appstream errors, I'm trying to fix them...\r"
					_nolibfuse_command_to_convert_to_type3_appimage
					if test -f ./*.AppImage; then
						_remove_info_files
						mv ./"$2" ./"$2".old
						mv ./*.AppImage ./"$2"
						echo " ◆ $(echo "$2" | tr a-z A-Z) has been converted to Type3 AppImage."
						_nolibfuse_if_appimage_has_been_converted
					else
						echo " 💀Errors while trying to export $(echo "$2" | tr a-z A-Z) from Type2 AppImage. Aborted."
						rm -R -f ./appimagetool ./squashfs-root; exit
					fi
				fi
			fi
		fi
	else
		echo " ⚠️ Error: \"$(echo "${2}" | tr a-z A-Z)\" is NOT installed."
		exit
	fi
}

##################################
# OPTIONS AVAILABLE IN THIS MODULE
##################################

case "$1" in
	'-b'|'backup') # DO A BACKUP OF AN INSTALLED APPLICATION
		_do_backup "${@}"
		shift
		;;

	'-o'|'overwrite') # OVERWRITE A NEW VERSION WITH THE PREVIOUS ONE FROM A BACKUP DONE WITH THE PREVIOUS OPTION
		_do_overwrite "${@}"
		shift
		;;

	'-R') # THIS OPTION REMOVES PROGRAMS WITHOUT ASKING
		while [ -n "$1" ]; do
			rm -f "$AMCACHEDIR"/remove-args
			echo "$@" | tr ' ' '\n' >> "$AMCACHEDIR"/remove-args && echo STOP >> "$AMCACHEDIR"/remove-args
			ARGS=$(tail -n +2 "$AMCACHEDIR"/remove-args)
			for arg in $ARGS; do
				if [ $arg == STOP ]; then
					_remove_check_removals
				else
					_REMOVE
					_remove_info_files
				fi
			done
		done
		shift
		;;

  	'-r'|'remove') # THIS OPTION ALLOWS YOU TO CHOOSE WHETHER TO REMOVE PROGRAMS OR NOT
		while [ -n "$1" ]; do
			rm -f "$AMCACHEDIR"/remove-args
			echo "$@" | tr ' ' '\n' >> "$AMCACHEDIR"/remove-args && echo STOP >> "$AMCACHEDIR"/remove-args
			ARGS=$(tail -n +2 "$AMCACHEDIR"/remove-args)
			for arg in $ARGS; do
				if [ $arg == STOP ]; then
					_remove_check_removals
				else
					_remove
					_remove_info_files
				fi
			done
		done
		shift
		;;

	'--rollback'|'downgrade') # THIS OPTION ALLOWS YOU TO DOWNGRADE THE INSTALLED APP TO A PREVIOUS VERSION, IF EXISTS
		_online_check
		while [ -n "$1" ]; do
			_do_rollback "${@}"
		done
		shift
		;;

	'lock') # LOCK THE INSTALLED VERSION
		_do_lock "${@}"
		shift
		;;

	'nolibfuse') # CONVERT TYPE2 APPIMAGES TO TYPE2
		_online_check
		while [ -n "$1" ]; do
			_do_nolibfuse "${@}"
		done
		shift
		;;

	'unlock') # REVERT THE OPTION "lock" ABOVE
		_do_unlock "${@}"
		shift
		;;
esac
